﻿// Decompiled with JetBrains decompiler
// Type: Netick.DoubleStats
// Assembly: Netick, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 6726ECA1-C773-4CF7-8952-E81B30D93B52
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.xml

using System;

#nullable disable
namespace Netick;

public class DoubleStats
{
  private double _count;
  private double _meanPrev;
  private double _meanCurr;
  private double _sPrev;
  private double _sCurr;
  private double _varianceCurr;
  private double _Sum;
  private double _SqrSum;
  private CircularList<double> _entries;

  public double Latest { get; private set; }

  public double Max { get; private set; }

  public double Min { get; private set; }

  public double Average { get; private set; }

  public double StdDeviation
  {
    get
    {
      int count = this._entries.Count;
      this._Sum = 0.0;
      this._SqrSum = 0.0;
      for (int i = 0; i < this._entries.Count; ++i)
      {
        this._Sum += this._entries[i];
        this._SqrSum += this._entries[i] * this._entries[i];
      }
      this.Average = this._Sum / (double) count;
      double d = (this._SqrSum - this._Sum * this._Sum / (double) count) / (double) count;
      return d < 0.0 ? 0.0 : Math.Sqrt(d);
    }
  }

  internal CircularList<double> Data => this._entries;

  internal CircularList<double> GetData() => this._entries;

  public DoubleStats(int windowSize = 128 /*0x80*/)
  {
    this._entries = new CircularList<double>(windowSize);
  }

  public void Update(double value)
  {
    this.Latest = value;
    if (this._entries.Count == this._entries.Capacity)
    {
      double entry1 = this._entries[0];
      if (entry1 == this.Min || entry1 == this.Max)
      {
        this.Min = double.MaxValue;
        this.Max = double.MinValue;
        for (int i = 0; i < this._entries.Capacity; ++i)
        {
          double entry2 = this._entries[i];
          if (entry2 < this.Min)
            this.Min = this._entries[i];
          if (entry2 > this.Max)
            this.Max = this._entries[i];
        }
      }
      this._Sum -= entry1;
      this._SqrSum -= entry1 * entry1;
    }
    if (value > this.Max)
      this.Max = value;
    if (value < this.Min)
      this.Min = value;
    this._entries.Add(value);
    int count = this._entries.Count;
    this._Sum += value;
    this._SqrSum += value * value;
    this.Average = this._Sum / (double) count;
    this._count = (double) count;
    if (count == 1)
    {
      this._meanCurr = value;
      this._sCurr = 0.0;
      this._varianceCurr = this._sCurr;
    }
    else
    {
      this._meanPrev = this._meanCurr;
      this._sPrev = this._sCurr;
      this._meanCurr = this.Average;
      this._sCurr = this._sPrev + (value - this._meanPrev) * (value - this._meanCurr);
      this._varianceCurr = this._sCurr / (this._count - 1.0);
    }
  }

  internal void ResetTo(double v)
  {
    for (int index = 0; index < this._entries.Capacity; ++index)
      this.Update(v);
  }

  public void Reset()
  {
    this._entries.Clear();
    this.Latest = 0.0;
    this.Average = 0.0;
    this.Max = 0.0;
    this.Min = 0.0;
    this._Sum = 0.0;
    this._SqrSum = 0.0;
  }
}
